#include "ModuleMgr.h"
#include <core/FileSys.h>
#include <core/Utility.h>
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonArray>
#include <QJsonObject>
#include <QLibrary>

ModuleMgr::ModuleMgr()
{
    loadModules();
}

ModuleMgr::~ModuleMgr()
{
}

IModule* ModuleMgr::module(const QString& id)
{
    auto iter = m_modules.find(id);
    if (iter != m_modules.end())
    {
        if (iter->module == nullptr)
            iter->module = loadModule(iter->id);

        return iter->module;
    }

    return nullptr;
}

void ModuleMgr::unloadModules()
{
    for (auto m : m_modules)
    {
        if ( m.module )
            m.module->unInitialize();
    }
}

ModuleMgr& ModuleMgr::instance()
{
    static ModuleMgr s_m;
    return s_m;
}

void ModuleMgr::loadModules()
{
    QString cfgPath = FileSys::instance()->appCfgDir() + "/modules.cfg";
    QJsonDocument doc = CoreUtility::openJsonDoc(cfgPath);
    if (doc.isNull())
    {
        logError(MODULE_NAME, "Load module configure failed!");
        return;
    }

    QJsonArray modules = doc.array();
    for (QJsonValue v : modules)
    {
        QJsonObject moduleObj = v.toObject();
        ModuleDef def;
        def.id = moduleObj["id"].toString();
        def.dllName = moduleObj["dll"].toString();
        def.dir = moduleObj["dir"].toString();
        def.loadBehavior = moduleObj["loadbehavior"].toInt();
        m_modules[def.id] = def;

        if (def.loadBehavior == 0)
            m_modules[def.id].module = loadModule(def.id);
    }
}

IModule* ModuleMgr::loadModule(const QString& id)
{
    QString dllPath = FileSys::instance()->runRootDir() + "/" + m_modules[id].dir + "/" + m_modules[id].dllName;
    QLibrary moduleDll(dllPath);
    if (!moduleDll.load())
    {
    //   logError(MODULE_NAME, "Load Module Failed:fail to load library: %ls\n%s", dllPath.toStdWString().c_str(), moduleDll.errorString().toUtf8());
        return nullptr;
    }

    typedef IModule* (*getModule)();
    getModule funPtr = (getModule)moduleDll.resolve("getModule");
    if (funPtr == nullptr)
    {
        logError(MODULE_NAME, "Load Module %s Failed:fail to find export function!", id.toStdString().c_str());
        return nullptr;
    }

    IModule* module = funPtr();
    if (module)
        module->initialize(getAppInstance());

    return module;
}
